import datetime
from typing import Any, MutableMapping

import jwt
from app.exceptions.http_resp import HttpResp
from app.exceptions.exception import AppException
from fastapi import Request
from app.config.settings import get_settings
from app.modules.auth.config import TokenType
from app.modules.auth.schema import PayloadSchema
'''
Header 用于设置签名算法及令牌类型，默认签名算法为 「 HS256 」，令牌类型可以设置为「 JWT 」

Payload 用于设置需要传递的数据，包含：iss 签发人、exp 过期时间、iat 签发时间等

iss (issuer)：发行者。
sub (subject)：主题，即该JWT所面向的对象。
aud (audience)：受众，即该JWT的目标接收者。
exp (expiration time)：过期时间。
nbf (not before)：生效时间。
iat (issued at)：签发时间。
jti (JWT ID)：唯一标识符。


Signature 用于对 Header 和 Payload 进行签名，默认使用的签名算法为 Header 中指定的算法
'''


class TokenManager():

    # def __init__(self) -> None:
    #     """
    #     :param secret_key: 密钥
    #     :param exp_time: 过期时间
    #     """

    #     get_settings().SECRET_KEY = "95ticket"
    #     self.exp = 60
    #     pass
    def create_token(self, identity: str | int | None = None,
                     expiration_minutes: int | None = None,
                     token_type: TokenType = TokenType.access_token) -> str:
        '''
        生成token

        :param identity: 用户ID，用于识别用户的身份
        :param expiration_minutes: Token的过期时间（分钟），用于控制Token的有效期
        :param token_type: Token的类型，指示Token的用途，如访问令牌或刷新令牌
        :return: 编码后的Token字符串，用于在用户和系统之间传递验证信息
        '''

        payload = self._create_payload(
            identity, expiration_minutes, token_type)
        return jwt.encode(payload=payload.model_dump(), key=get_settings().SECRET_KEY, algorithm=get_settings().ALGORITHM)

    def _create_payload(self, identity: int | str | None, expiration_minutes: int | None, token_type: TokenType = TokenType.access_token) -> PayloadSchema:

        if expiration_minutes:
            exp = datetime.datetime.now() + datetime.timedelta(minutes=expiration_minutes)

        elif not expiration_minutes:
            exp = (datetime.datetime.now()
                   + datetime.timedelta(
                minutes=get_settings().ACCESS_TOKEN_EXPIRE_MINUTES
                if token_type == TokenType.access_token else get_settings().REFRESH_TOKEN_EXPIRE_MINUTES
            )
            )
        payload = PayloadSchema(
            iss=get_settings().domain,
            sub=str(identity),
            aud=get_settings().domain,
            exp=exp.astimezone().timestamp(),
            nbf=datetime.datetime.now().astimezone().timestamp(),
            iat=datetime.datetime.now().astimezone().timestamp(),
            jti="1234567890",
            token_type=token_type,
            identity=identity
        )
        return payload

    def get_identity(self, token: str) -> str:
        '''获取identity'''
        try:
            payload = self._parse_payload(token)
            # print(token)
        except Exception as e:
            raise AppException(exc=HttpResp.TOKEN_INVALID)
        return payload.get("identity")

    def _parse_payload(self, token: str):
        '''解析负载'''
        try:
            token = token.split(" ")[1]
            return jwt.decode(token, get_settings().SECRET_KEY, algorithms=[get_settings().ALGORITHM], options={"verify_aud": False})
            # print(token)
        except Exception as e:
            raise AppException(exc=HttpResp.TOKEN_INVALID)

    def is_invalidate_token(self, token: str):
        '''无效验证'''
        if self.get_identity(token):
            raise AppException(exc=HttpResp.FAILED, msg="token无效")
        return True

    def is_expiration_token(self, token: str):
        '''过期验证'''
        try:
            current_time = datetime.datetime.now()
            if current_time > datetime.datetime.fromtimestamp(self._parse_payload(token).get("exp", 0)):
                raise BaseException("token过期")
            pass
        except Exception as e:
            pass
        finally:
            pass
        pass

    # def is_exist_token(self, request: Request):
    #     '''验证token 是否存在'''

    #     token = request.headers.get("Authorization")
    #     if not token:
    #         raise AppException(HttpResp.TOKEN_EMPTY)

    #     return token


token_manager = TokenManager()
